package com.apes.framework.plugin.ftp;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import org.apache.commons.net.ftp.FTPClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;

/**
 * FTP工具类
 */
@Component
public class FtpUtil {
    private final FtpPool pool;

    @Value("${apes.excel.pageSize:5000}")
    private int pageSize;

    @Value("${apes.excel.sheetSize:1000000}")
    private int sheetSize;

    public FtpUtil(FtpPool pool) {
        this.pool = pool;
    }

    /**
     * 向FTP服务器上传Excel文件
     *
     * @param head     Excel 头部
     * @param fileName Excel 文件名
     * @param rs       ResultSet
     * @param func     回调函数
     * @return 是否调用成功
     */
    public boolean uploadExcel(List<List<String>> head, String fileName, ResultSet rs, Function<ResultSet, Collection> func) throws Exception {
        fileName = new String(fileName.getBytes(), StandardCharsets.UTF_8);
        FTPClient ftpClient = pool.getFTPClient();
        if (ftpClient == null) return false;
        OutputStream os = null;
        try {
            os = ftpClient.storeFileStream(fileName);
            ExcelWriter writer = new ExcelWriterBuilder()
                    .excelType(ExcelTypeEnum.XLSX)
                    .file(os)
                    .autoCloseStream(false)
                    .head(head)
                    .build();
            write(writer, rs, func);    // 分页写入
            writer.finish();
            boolean result = ftpClient.completePendingCommand();
            if (!result) {
                ftpClient.deleteFile(fileName);
            }
            return result;
        } catch (Exception e) {
            if (os != null) {
                ftpClient.deleteFile(fileName);
            }
            throw e;
        } finally {
            /** 归还资源 **/
            pool.returnFTPClient(ftpClient);
        }
    }

    private void write(ExcelWriter writer, ResultSet rs, Function<ResultSet, Collection> func) throws Exception {
        Integer i = 0;
        List data = null;
        WriteSheet writeSheet = null;
        while (rs.next()) {
            if (i % pageSize == 0) {
                data = new ArrayList();
            }
            if (i % sheetSize == 0) {
                int sheetNo = i / sheetSize;
                writeSheet = EasyExcel.writerSheet(sheetNo, String.format("第%d页", sheetNo + 1)).build();
            }
            data.add(func.apply(rs));   // 回调添加每一行的数据
            i++;
            if (i % pageSize == 0) {
                writer.write(data, writeSheet);
            }
        }
        if (data != null && data.size() > 0 && data.size() < pageSize) {
            writer.write(data, writeSheet);
        }
    }

    public boolean removeFile(String fileName) throws IOException {
        boolean flag = false;
        FTPClient ftpClient = pool.getFTPClient();
        if (ftpClient == null) return flag;

        try {
            fileName = new String(fileName.getBytes(), StandardCharsets.UTF_8);
            flag = ftpClient.deleteFile(fileName);
        } catch (Exception e) {
            throw e;
        } finally {
            /** 归还资源 **/
            pool.returnFTPClient(ftpClient);
        }
        return flag;
    }

}
